#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
Model模块，定义了数据库连接和操作
'''

import MySQLdb


class ConnectBase(object):
    '数据库连接类，定义了连接和关闭'
    def __init__(self):
        from igor import const

        self.conn = MySQLdb.connect(**const.mysqldb)
        self.conn.autocommit(True)

    def check_conn(self):
        '检测连接是否正常，如果连接异常，则尝试重连'
        from igor import const
        from igor import logging

        try:
            self.conn.ping(True)
        except Exception, expt:
            logging.log('ConnectBase.cursor():')
            logging.log(str(expt))
            self.conn = MySQLdb.connect(**const.mysqldb)
            self.conn.autocommit(True)

    @property
    def cursor(self):
        '获取连接cursor'

        return self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)


class ModelBase(object):
    '数据库模型基类，定义了连接和关闭和一些基本操作'
    TABLE_NAME = None

    def __init__(self):
        Conn.check_conn()
        self._conn = Conn.conn
        self._cursor = Conn.cursor

    @staticmethod
    def transaction(func):
        '声明事务的装饰器，检测到异常则自动回滚事务'
        def dec(self, *args, **kwargs):
            '新函数'
            try:
                self._conn.begin()
                res = func(self, *args, **kwargs)
                self._conn.commit()
                return res
            except Exception:
                self._conn.rollback()
                # 不忽略异常
                raise
        return dec

    def select(self, where_dict=None, columns=None, more=None, table=None):
        '根据传入参数获取记录，此方法只获取一个记录'
        records = self.select_all(where_dict, columns, more, table)
        record = records[0] if records else None
        return record

    def select_all(self, where_dict=None, columns=None, more=None, table=None):
        '根据传入参数获取记录，此方法获取所有记录'
        if not table:
            table = self.TABLE_NAME
        if not where_dict:
            where_dict = {}

        from_str = ', '.join(columns) if columns else '*'
        where_str = ' and '.join([k + '=%s' for k in where_dict])

        sql_str = 'select %s from `%s`' % (from_str, table)
        if where_dict:
            sql_str += ' where ' + where_str
        if more:
            sql_str += ' ' + more

        if where_dict:
            self._cursor.execute(sql_str, where_dict.values())
        else:
            self._cursor.execute(sql_str)
        records = self._cursor.fetchall()

        return records

    def insert_from_dict(self, info_dict, table=None):
        '根据传入的字典插入数据'
        if not table:
            table = self.TABLE_NAME

        sql_str = 'insert into `%s`(%s) value(%s)'
        column_str = ', '.join(info_dict.keys())
        value_str = ', '.join(['%s'] * len(info_dict))
        sql_str = sql_str % (table, column_str, value_str)

        count = self._cursor.execute(sql_str, info_dict.values())
        return count

    def update_from_dict(self, info_dict, where_dict, table=None):
        '根据传入的字典更新数据'
        if (not info_dict) or (not where_dict):
            # 禁止不设定条件
            return None
        if not table:
            table = self.TABLE_NAME

        sql_str = 'update `%s` set %s where %s'
        set_str = ', '.join([k + '=%s' for k in info_dict])
        where_str = ' and '.join([k + '=%s' for k in where_dict])
        sql_str = sql_str % (table, set_str, where_str)

        count = self._cursor.execute(
                sql_str,
                info_dict.values() + where_dict.values())
        return count


class ModelSession():
    'Session模型，用redis实现'
    def __init__(self):
        import redis
        from igor import const

        self._redis = redis.StrictRedis(**const.redis)

    def create(self, data, expir_sec):
        '创建一个Session'
        import uuid
        import cPickle

        # 选择一个不重复的SN号
        while True:
            sn_num = uuid.uuid4().hex
            record = self._redis.get(sn_num)
            if not record:
                break

        content = cPickle.dumps(data)
        self._redis.setex(sn_num, expir_sec, content)

        return sn_num

    def get_session_info(self, sn_num):
        '根据sn取Session信息'
        import cPickle

        content = self._redis.get(sn_num)
        if not content:
            return None
        data = cPickle.loads(content)
        return data

    def clear(self, sn_num):
        '清除该Session'
        self._redis.delete(sn_num)

# 创建全局连接，设置自动提交
Conn = ConnectBase()
